package mrpheu.demo.server.implement;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.net.SocketTimeoutException;

import mrpheu.demo.basic.interfaces.IMrPheuIO;
import mrpheu.demo.basic.interfaces.IMrPheuOPC;
import mrpheu.demo.server.bean.MessageItem;
import mrpheu.demo.server.classes.ProcessBasicClient;
import mrpheu.demo.server.classes.ThreadPoolChat;
import mrpheu.demo.server.constants.UsingServerFlag;
import mrpheu.demo.server.interfaces.IZoneClient;
import mrpheu.demo.server.main.ServerChat;


public class ProcessUDPClient extends ProcessBasicClient implements IMrPheuIO, IZoneClient, IMrPheuOPC, Runnable {
    private DatagramSocket socket;
    private int portListen;
    private DatagramPacket packet;
    private byte[] buf;
    private final int TIME_OUT = 5000;
    
    public ProcessUDPClient(int id, DatagramSocket socket, DatagramPacket packet, int portListen) {
        super(id, UsingServerFlag.UDP);
        this.socket = socket;
        this.packet = packet;
        this.portListen = portListen;
        //this.threadPool = threadPool;
        this.buf = new byte[512];
    }
    
    private boolean off = false; // default
    
    public boolean isOff() {
        return off;
    }

//    public static void setOff(boolean off) {
//        this.off = off;
//    }

    @Override
    public boolean sendData(Object data) {
        MessageItem messageItem = (MessageItem)data;
        byte[] message = messageItem.getMessage().getBytes();
        DatagramPacket packet = new DatagramPacket(message, message.length, this.packet.getAddress(), this.portListen);
        try {
            this.socket.send(packet);
            System.out.println("Send data success");
        } catch (IOException e) {
            System.out.println("Send data fail");
            return false;
        }
        return true;
    }

    @Override
    public Object receiveData() {
        try {
            return receiveBasic();
        } catch (SocketTimeoutException e) {
            return null;
        } catch (IOException e) {
            return null;
        }
    }

    @Override
    public void update(MessageItem data) {
        sendData(data);
    }
    
    private Object receiveBasic() throws SocketTimeoutException, IOException {
        DatagramPacket packet = new DatagramPacket(buf, buf.length);
        //System.out.println("Waiting data...");
        this.socket.receive(packet);
        System.out.println("Received: " + new String(packet.getData()));
        return packet;
    }
    
    private boolean sendTransaction(MessageItem messageItem) {
        int count = 0;
        while(count <= 3) {
            if(this.sendData(messageItem)) {
                try {
                    this.socket.setSoTimeout(TIME_OUT);
                } catch (SocketException e1) {
                    System.out.println("Socket exception");
                    return false;
                }
                while(true) {
                    try {
                        System.out.println("Waiting ACK...");
                        if(receiveBasic() != null) {
                            System.out.println("Send success");
                            return true;
                        }
                    } catch (SocketTimeoutException e) {
                        count++;
                        break;
                    } catch (IOException e) {
                        return false;
                    }
                }
            }
        }
        return false;
    }

    @Override
    public boolean open() {
        //this.threadPool.execute(this);
//        MessageItem messageItem = new MessageItem(0, "open");
//        System.out.println("Send ack connect...");
        //byte[] buf = new byte[512];
        //DatagramPacket packet = new DatagramPacket(buf, buf.length);
        try {
            this.socket.send(this.packet);
        } catch (IOException e) {
            return false;
        }
        return true;
    }

    @Override
    public void process() {
        while (!this.off) {
            DatagramPacket data = null;
            data = (DatagramPacket)receiveData();
            byte[] dataByte = data.getData();
            String dataStr = new String(dataByte);
            System.out.println("Receive from client: " + dataStr);
            //sendData(new MessageItem(0, "ACK"));
            String str = new String(data.getData());
            MessageItem messageItem = MessageItem.processData(str);
            //receiveData();
            try {
                System.out.println("Insert to queue");
                ServerChat.messageList.put(messageItem);
            } catch (InterruptedException e) {
                System.out
                        .println("Server insert data to the queue fail!");
            }
        }
        this.close();
    }

    @Override
    public boolean close() {
        if(this.socket != null) {
            this.socket.close();
        }
        return true;
    }

    @Override
    public void run() {
        System.out.println("Run...");
        this.open();
        this.process();
        //this.close();
    }

}
